#include "expression.h"
#include "subexpression.h"
#include "literalexpression.h"
#include "addexpression.h"
#include "mulexpression.h"
#include "divexpression.h"
#include "expexpression.h"
#include "orexpression.h"
#include <sstream>
#include "error.h"
typedef Expression* (*f)(Expression *lhs, Expression *rhs);
typedef struct Operator
{
	f createPtr;	
	const char *name;
};
//template <typename T>
//typedef struct Operator
//{
//	const char *text
//};
//
//Operator *operators[7] = {
//
//	{ AddExpression, "+"}
//}

Expression *createAdd(Expression *lhs, Expression *rhs)
{
	return new AddExpression(lhs, rhs);
}

Expression *Expression::parse(const char *string)
{
	return Expression::parse2(string, strlen(string));
	//return Expression::parseInternal(string, string);
}

const char* operators[] =
{
	"-",
	"+",
	"%",
	"/",
	"*"
};

Expression *Expression::parse2(const char *input, int len)
{
	Expression *result = NULL;
	bool negate = false;

	char *precedent_operator = NULL;
	int operator_index = 5;
	const char *cp = input;
	const char *end = cp + len;
	//while(cp != end)
	//{
		if(*cp == '(')
		{
			int open = 1;
			const char *p = ++cp;
			while(open > 0)
			{
				if(*p == '(')
					open++;
				else if(*p == ')')
					open--;
				p++;
			}
			result = Expression::parse2(cp, p - cp);
			cp += p-cp;
		}
		for(int i = 0; i < operator_index; i++)
		{
			char *op_pos = const_cast<char*>(strstr(cp, operators[i]));
			if(op_pos && (op_pos - input) < len)
			{
				precedent_operator = op_pos;
				operator_index = i;
			}
		}

		if(precedent_operator == NULL)
		{
			if(Expression::isNumber(*cp))
			{
				float value;

				if(!Expression::parseValue<float>(value, &cp, std::dec))
				{
					throw new UnexpectedTokenException(0);
				}

				if(negate)
					value = -value;

				result = new LiteralExpression(value);
			}
		}
		else
		{
			int lhs_len = precedent_operator - input;
			int rhs_len = len - lhs_len - 1;
			Expression *lhs = Expression::parse2(input, lhs_len);
			Expression *rhs = Expression::parse2(precedent_operator + 1, rhs_len);
			switch(operator_index)
			{
			case 0:
				result = new SubExpression(lhs, rhs);
				break;
			case 1:
				result = new AddExpression(lhs, rhs);
				break;
			case 2:
				result = NULL;
				break;
			case 3:
				result = new DivExpression(lhs, rhs);
				
				break;
			case 4:
				result = new MulExpression(lhs, rhs);
				break;
			}
		}
		
	//}
	return result;
}

Expression *Expression::parseSubexpression(const char **input)
{
	int subexpressionLength = 0;
	int open = 1;

	const char *cp = ++*input;
	do
	{
		if(*cp == '(')
			open++;
		else if(*cp == ')')
			open--;

	}while(*++cp != '\0' && open != 0);

	if(open)
		throw new InvalidExpressionException("Expression contains unclosed parentheses.");
	subexpressionLength = cp - *input;

	char *subp = new char[subexpressionLength];
	memcpy(subp, *input, subexpressionLength - 1);
	subp[subexpressionLength - 1] = '\0';

	*input += subexpressionLength;

	Expression *result = Expression::parse(subp);

	delete[] subp;

	return result;
}

Expression *Expression::parseInternal(const char *p, const char *orig)
{
	Expression *lhs = NULL;;
	bool negate = false;

	while(*p && !lhs)
	{
		if(*p == '(')
		{
			// If we encounter a "(", parse the subexpression separately.
			lhs = Expression::parseSubexpression(&p);
		}
		else if(Expression::isNumber(*p))
		{ 
			float value;

			if(!Expression::parseValue<float>(value, &p, std::dec))
			{
				throw new UnexpectedTokenException(p - orig);
			}

			if(negate)
				value = -value;

			lhs = new LiteralExpression(value);
		}
		else if(*p == 'B' || *p == 'b')
		{
			// If token is prefixed by 'B' or 'b', it should be interpreted as a binary value.
			int value;

			if(!Expression::parseBinary(value, &++p))
			{
				throw new UnexpectedTokenException(p - orig);
			}

			if(negate)
				value = -value;

			lhs = new LiteralExpression(value);
		}
		else if(Expression::isWhitespace(*p) && !negate)
		{
			p++;
		}
		else if(*p == '-' && !negate)
		{
			negate = true;
			p++;
		}
		else
		{
			throw new UnexpectedTokenException(p - orig);
		}
	}

	if(!lhs)
	{
		throw new EOEException;
	}

	Expression *subtree = NULL;
	char operation = 0;
	while(*p && !operation)
	{
		if(Expression::isOperation(*p))
		{
			operation = *p++;
		}
		else if(Expression::isWhitespace(*p))
		{
			*p++;
		}
		else
		{
			throw new UnexpectedTokenException(p - orig);
		}
	}

	// Check if we, at this point, have reached the end of the expression.
	if(!*p)
	{
		// If we have found an operation, throw an "unexpected end-of-expression" exception.
		if(operation)
		{
			throw new EOEException;;
		}
		else
		{
			subtree = lhs;
		}
	}
	else
	{
		// Parse right hand side of expression.
		Expression *rhs = Expression::parseInternal(p, orig);

		// Now we have the left and right side of the expression and can create the appropriate operation.
		switch(operation)
		{
		case '+':
			subtree = new AddExpression(lhs, rhs);
			break;
		case '-':
			subtree = new SubExpression(lhs, rhs);
			break;
		case '*':
			subtree = new MulExpression(lhs, rhs);
			break;
		case '/':
			subtree = new DivExpression(lhs, rhs);
			break;
		case '^':
			subtree = new ExpExpression(lhs, rhs);
			break;
		case '|':
			subtree = new OrExpression(lhs, rhs);
			break;
		}
	}
	return subtree;
}